package com.gutai.admin.dao.impl;

import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;

import com.gutai.admin.common.util.CollectionUtil;
import com.gutai.admin.dao.CustomJpaRepository;


/**
 * 
 * 自定义的查询接口实现类
 * 
 * <pre>
 * HISTORY
 * ****************************************************************************
 *  ID    DATE            PERSON            REASON
 *  1     2019年3月6日         LA.01367604           Create
 * ****************************************************************************
 * </pre>
 * 
 * @author LA.01367604
 * @version 1.0
 */
public class BaseCustomJpaDao<T> extends SimpleJpaRepository<T, Integer> implements CustomJpaRepository<T> {

    // 实体管理类，对持久化实体做增删改查，自动义sql操作模板所需要的核心类
    private EntityManager entityManager;
    
    public BaseCustomJpaDao(Class<T> domainClass, EntityManager em) {
        super(domainClass, em);
        this.entityManager = em;
    }

    @Override
    public EntityManager getEntityManager() {
        return entityManager;
    }

    @Override
    public Page<T> queryPage(int pageIdx, int pageSize) {
        Pageable pageable = PageRequest.of(pageIdx - 1, pageSize);
        return super.findAll(pageable);
    }

    @Override
    public Page<T> queryPage(int pageIdx, int pageSize, Sort sort) {
        Pageable pageable = PageRequest.of(pageIdx - 1, pageSize, sort);
        return super.findAll(pageable);
    }

    @Override
    public List<T> queryListWithConds(Map<String, Object> fieldsMap) throws Exception {
        Specification<T> spec = createSpec(fieldsMap, null);
        return super.findAll(spec);
    }

    @Override
    public Page<T> queryPage(Map<String, Object> fieldsMap, int pageIdx, int pageSize) throws Exception {
        Specification<T> spec = createSpec(fieldsMap, null);
        return queryPageWithSpec(spec, pageIdx - 1, pageSize);
    }

//    private Example<T> createExample(Map<String, Object> fieldsMap) throws Exception {
//        Class<T> objClass = super.getDomainClass();
//        T obj = objClass.newInstance();
//        for (Entry<String, Object> entry : fieldsMap.entrySet()) {
//            Field field = objClass.getDeclaredField(entry.getKey());
//            field.setAccessible(true);
//            field.set(obj, entry.getValue());
//        }
//        return Example.of(obj, ExampleMatcher.matchingAll());
//    }
    private Specification<T> createSpec(Map<String, Object> whereFieldsMap, Set<String> selectFields) {
        return new Specification<T>() {

            @Override
            public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder criteriaBuilder) {
                if (CollectionUtil.isNotEmpty(selectFields)) {
                    for (String field : selectFields) {
                        query.select(root.get(field));
                    }
                }
                if (whereFieldsMap != null && !whereFieldsMap.isEmpty()) {
                    for (Entry<String, Object> field : whereFieldsMap.entrySet()) {
                        query.where(criteriaBuilder.equal(root.get(field.getKey()), field.getValue()));
                    }
                }
                return query.getRestriction();
            }
            
        };
    }

    @Override
    public Page<T> queryPageWithSelect(Set<String> fields, int pageIdx, int pageSize) {
        Specification<T> spec = createSpec(null, fields);
        return queryPageWithSpec(spec, pageIdx - 1, pageSize);
    }
    
    @Override
    public Page<T> queryPageWithSpec(Specification<T> spec, int pageIdx, int pageSize) {
        Pageable pageable = PageRequest.of(pageIdx - 1, pageSize);
        return super.findAll(spec, pageable);
    }

    @Override
    public Page<T> queryPageWithSpec(Specification<T> spec, int pageIdx, int pageSize, Sort sort) {
        Pageable pageable = PageRequest.of(pageIdx - 1, pageSize, sort);
        return super.findAll(spec, pageable);
    }

    @Override
    public List<T> queryWithSql(String sql) {
        return entityManager.createQuery(sql).getResultList();
    }

    @Override
    public T findById(int id) {
        return super.findById(id).orElse(null);
    }

//    @Override
//    public void delete(Map<String, Object> fieldsMap) {
//        // TODO 自动生成的方法存根
//    }

}
